<?php

namespace app\common\model;

use \think\facade\Cache;

class User extends \think\Model
{
    /**
     * Token缓存的前缀
     */
    const AUTHKEY_PREFIX = "AUTHKEY";

    /**
     * 缓存组标记的前缀
     */
    const AUTHKEY_GROUP = "LOGIN_TOKEN_";

    /**
     * Token的最长生存时间
     */
    const TOKEN_TTL = 2400;

    /**
     * 检查Token的间隔
     */
    const TOKEN_CHECK_INTERVAL = 300;

    protected $pk = "user_name";

    protected $visible = ['user_name', 'status','level'];

    public function getStatusAttr($value)
    {
        return !!$value;
    }

    public function setStatusAttr($value)
    {
        return $value ? 1 : 0;
    }

    /**
     * 登陆接口
     *
     * @param [type] $userName
     * @param [type] $password
     * @return string token
     */
    public function login($userName, $password)
    {
        if ($userName === null) {
            $this->error = "用户名不能为空";
            return false;
        }
        if ($password === null) {
            $this->error = "密码不能为空";
            return false;
        }
        $user = $this->where(['user_name' => $userName, 'password' => md5($userName . $password)])->find();
        if ($user === null) {
            $this->error = "登陆失败,可能是密码错误或账号不存在";
            return false;
        }
        $user->setAttr('last_login', time());
        $user->save();
        $arr = [
            'user_name' => $user->getAttr('user_name'),
            'password' => $user->getAttr('password'),
            'level' => $user->getAttr('level'),
            'lastlogin' => $user->getAttr('last_login'),
        ];
        $token = md5(implode("&", $arr));
        $arr['lasttime'] = $arr['lastlogin'];   //用于每隔一段时间检查token是否失效,并及时更新token的有效期
        User::clearTokens($arr['user_name']);
        \cache(User::AUTHKEY_PREFIX . $token, $arr, User::TOKEN_TTL, User::AUTHKEY_GROUP . $arr['user_name']);
        return $token;
    }

    /**
     * 重置用户密码
     *
     * @return string|false 如果重置密码成功,返回新的随机密码,如果重置密码失败,返回false
     */
    public function resetPassword($userName){
        $user=$this->get($userName);
        if (!$user){
            $this->error="找不到指定用户";
            return false;
        }
        $password =getRandomStr(6);
        $user->password=md5($userName .  md5($password));
        $user->save();
        $this->clearTokens($userName);
        return $password;
    }

    /**
     * 检查一个token是否有效,并延长缓存的有效期
     *
     * @param [type] $token
     * @param mixed $targetLevel 目标的权限等级,如果为null,则表示不进行检查
     * @return int 返回状态码,STATUS_OK表示成功
     */
    public static function checkToken($token, $targetLevel = null)
    {
        if ($token === null || !($cache = cache(User::AUTHKEY_PREFIX . $token))) {
            return STATUS_AUTH;
        }

        if (time() - $cache['lasttime'] > User::TOKEN_CHECK_INTERVAL) {
            //每五分钟校验一次缓存,并检查是否存在互踢的情况，并更新缓存
            $userModel = User::get($cache['user_name']);
            if ($userModel->getAttr('password') !== $cache['password'] || $userModel->getAttr('last_login') !== $cache['lastlogin']) {
                User::clearTokens($cache['user_name']);
                return STATUS_AUTH;
            }
            $cache['lasttime'] = time();
            \cache(User::AUTHKEY_PREFIX . $token, $cache, User::TOKEN_TTL, User::AUTHKEY_GROUP . $cache['user_name']);
        }

        if ($targetLevel !== null && $cache['level'] > $targetLevel) {
            return STATUS_FORBIDDEN; //权限不足
        }

        return STATUS_OK;
    }

    /**
     * 清除某个用户的token,执行此操作后,用户将会下线
     * 此函数主要用于已知用户名踢人
     *
     * @return void
     */
    public static function clearTokens($username)
    {
        Cache::clear(User::AUTHKEY_GROUP . $username);
    }


    /**
     * 清除某个用户的token,执行此操作后,用户将会下线
     * 此函数主要用于已知token进行下线处理
     *
     * @return void
     */
    public static function clearToken($token)
    {
        cache(User::AUTHKEY_PREFIX . $token, null);
    }
}
